package com.tank;

import com.tank.net.Client;
import com.tank.net.msg.TankDieMsg;
import com.tank.net.msg.TankDirectionChangeMsg;
import com.tank.net.msg.TankStartMovingMsg;
import com.tank.net.msg.TankStoppedMsg;

import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.*;


/**
 * @author CaoBaoYin
 * @since 21/8/13 10:32
 */
public class TankFrame extends Frame {
    public static final TankFrame INSTANCE = new TankFrame();
    Random random = new Random();
    private Tank mainTank = new Tank(random.nextInt(GAME_WIDTH), random.nextInt(GAME_HEIGHT), DirectionEnum.values()[random.nextInt(4)], GroupEnum.values()[random.nextInt(2)], this);
    public LinkedList<Bullet> bulletList = new LinkedList<>();
    public Map<UUID, Tank> tankMap = new HashMap<>();
    LinkedList<Explode> explodeList = new LinkedList<>();

    static final int GAME_WIDTH = 800, GAME_HEIGHT = 600;

    private TankFrame() throws HeadlessException {
        setSize(GAME_WIDTH, GAME_HEIGHT);//窗口大小
        setResizable(false);// 窗口不可以改变大小
        setTitle("tank war");// 窗口标题
        // setVisible(true);// 设置窗口可见，窗口就可以显示了
        addKeyListener(new MyKeyListener());
        addWindowListener(new WindowAdapter() {
            // 窗口点击×执行这个方法
            @Override
            public void windowClosing(WindowEvent e) {
                exit();
            }
        });
    }

    /**
     * 退出程序
     */
    public void exit (){
        // 通知其他客户端，主站坦克死亡
        Client.INSTANCE.sendMsg(new TankDieMsg(TankFrame.INSTANCE.getMainTank().getId()));
        // 退出程序
        System.exit(0);
    }

    class MyKeyListener extends KeyAdapter {
        boolean bL = false;
        boolean bR = false;
        boolean bU = false;
        boolean bD = false;
        @Override
        public void keyPressed(KeyEvent e) {
            System.out.println("key pressed");
            int keyCode = e.getKeyCode();
            switch (keyCode) {
                case KeyEvent.VK_LEFT:{
                    bL = true;
                    break;
                }
                case KeyEvent.VK_RIGHT:{
                    bR = true;
                    break;
                }
                case KeyEvent.VK_UP:{
                    bU = true;
                    break;
                }
                case KeyEvent.VK_DOWN:{
                    bD = true;
                    break;
                }
                default:{

                }
            }

            setMainTankDirection();

            new Thread(()->new Audio("audio/tank_move.wav").play()).start();
        }

        @Override
        public void keyReleased(KeyEvent e) {
            System.out.println("key release");
            int keyCode = e.getKeyCode();
            switch (keyCode) {
                case KeyEvent.VK_LEFT:{
                    bL = false;
                    break;
                }
                case KeyEvent.VK_RIGHT:{
                    bR = false;
                    break;
                }
                case KeyEvent.VK_UP:{
                    bU = false;
                    break;
                }
                case KeyEvent.VK_DOWN:{
                    bD = false;
                    break;
                }
                case KeyEvent.VK_CONTROL:{// 不用pressed是因为按下不释放会一直调用pressed方法
                    mainTank.fire();
                    break;
                }
                default:{

                }
            }
            setMainTankDirection();
        }

        private void setMainTankDirection() {
            if (bL || bR || bU || bD) {
                DirectionEnum oldDir = mainTank.getDir();

                if (bL) mainTank.setDir(DirectionEnum.LEFT);
                if (bR) mainTank.setDir(DirectionEnum.RIGHT);
                if (bU) mainTank.setDir(DirectionEnum.UP);
                if (bD) mainTank.setDir(DirectionEnum.DOWN);

                if (! oldDir.equals(mainTank.getDir())) {
                    Client.INSTANCE.sendMsg(new TankDirectionChangeMsg(mainTank));
                }

                if (! mainTank.isMoving()) {
                    Client.INSTANCE.sendMsg(new TankStartMovingMsg(mainTank));
                }

                mainTank.setMoving(true);
            } else {
                if (mainTank.isMoving()) {
                    Client.INSTANCE.sendMsg(new TankStoppedMsg(mainTank));
                }

                mainTank.setMoving(false);
            }


        }
    }

    /**
     * 游戏 中 “双缓冲”概念解决屏幕闪
     * 闪 的原因是因为面刷新重画时，上次还没画完，这次又开始进行了刷新重画，就造成了闪烁；
     * 通过创建一种图片（占用内存），将内容都画到图片上，再将图片一次性画到界面上
     *
     * 重画的时候其实会先调 update，再调用paint
     * 我们截获了update，先画出画面图片在内存中，图片大小和游戏画面一致。然后调用paint
     * 然后把内存内容复制到显存（就画到屏幕上了）
     */
    Image screenImage = null;
    @Override
    public void update(Graphics g) {
        if (screenImage == null)
            screenImage = this.createImage(GAME_WIDTH, GAME_WIDTH);

        /*创建一张照片，并获取照片中的画笔*/
        Graphics gScreen = screenImage.getGraphics();
        Color c = gScreen.getColor();
        gScreen.setColor(Color.BLACK);
        gScreen.fillRect(0,0, GAME_WIDTH, GAME_HEIGHT);// 用照片中的画笔画纯色背景
        gScreen.setColor(c);

        paint(gScreen);// 使用图片画笔画出图片

        // 系统画笔渲染图片
        g.drawImage(screenImage, 0, 0, null);
    }

    @Override
    public void paint(Graphics g) {
        Collection<Tank> tankCollection = tankMap.values();
        // System.out.println("paint");
        Color c = g.getColor();
        g.setColor(Color.WHITE);
        g.drawString("子弹数量："+bulletList.size()+", 地方坦克数量："+ tankCollection.size() + ", 爆炸的数量："+explodeList.size(), 60, 60);
        g.setColor(c);

        // 主站坦克
        // mainTank.paint(g);

        // 绘制坦克
        for (Iterator<Tank> it = tankCollection.iterator(); it.hasNext(); ) {
            Tank tank = it.next();
            if (! tank.isLiving()) {
                it.remove();
            }

            //TODO 坦克随机方向
            tank.paint(g);
        }

        // 绘制子弹
        for (Iterator<Bullet> it = bulletList.iterator(); it.hasNext(); ) {
            Bullet bullet = it.next();
            if (! bullet.isLive()) {
                it.remove();
            }

            bullet.paint(g);
        }

        // 绘制爆炸
        for (int i = explodeList.size() - 1; i >= 0 ; i--) {
            Explode explode = explodeList.get(i);
            explode.paint(g);
        }

        // 子弹和坦克是否碰撞
        for (Bullet bullet : bulletList) {
            for (Tank tank : tankCollection) {
                bullet.collideWith (tank);
            }
        }

    }

    public Tank getMainTank() {
        return mainTank;
    }

    public void setMainTank(Tank mainTank) {
        this.mainTank = mainTank;
    }
}
